/*实现muduo库*/
#pragma once
#include<muduo/net/TcpClient.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpConnection.h>
#include <muduo/net/Buffer.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/net/EventLoopThread.h>
#include<muduo/net/TcpServer.h>

#include"1.detail.hpp"
#include"2.fields.hpp"
#include"3.abstract.hpp"
#include"4.message.hpp"
#include<mutex>
#include<unordered_map>

namespace rpcType
{
    //网络缓冲区
    class MuduoBuffer:public BaseBuffer
    {
        public:
        using ptr = std::shared_ptr<MuduoBuffer>;
        //构造
        MuduoBuffer(muduo::net::Buffer *buf)
        :_buf(buf)
        {}
        virtual size_t readableSize()override//可读大小
        {
            return _buf->readableBytes();
        }
        virtual int32_t peekInt32() override
        {
            return _buf->peekInt32();
        } 
        virtual void retrieveInt32()override//取出4字节
        {
            return _buf->retrieveInt32();
        }
        virtual int32_t readInt32() override//读4字节
        {
            return _buf->readInt32();
        }
        virtual std::string retrieveasString(size_t len) override//取出len字符串
        {
            return _buf->retrieveAsString(len);
        }
        private:
        muduo::net::Buffer *_buf;
    };
    class BufferFactory
    {
        public:
        template<typename ...Args>
        static BaseBuffer::ptr cerate(Args&& ...args)
        {
            return std::make_shared<MuduoBuffer>(std::forward<Args>(args));
        }
    };
    //协议
    class LVProtocol :public BaseProtocol
    {
        public:
        using ptr = std::shared_ptr<LVProtocol>;
        //判断缓冲区中的数据量是否足够处理一条消息
        //可处理数据
        virtual bool canProcessed(const BaseBuffer::ptr &buf) override
        {
            if(buf->readableSize()>lenFieldsLength)
            {
                return false;
            }
            int32_t total_len = buf->peekInt32();//总长度
            if(buf->readableSize()<(total_len+lenFieldsLength))//可读大小
            {
                return false;
            }
            return true;
        }

        //正在处理消息
        virtual bool onMessage(const BaseBuffer::ptr &buf,BaseMessage::ptr&msg) override
        {
            //调用onMessage时 默认缓冲区中的数据是完整的一条消息
            int32_t total_len = buf->readInt32();//读取总长度
            MType mtype = (MType)buf->readInt32();//读取数据类型
            int32_t idlen = buf->readInt32();//读取id长度
            int32_t body_len = total_len-idlen-idlenFieldsLength-mtypeFieldsLength;
            std::string id = buf->retrieveasString(idlen);
            std::string body = buf->retrieveasString(body_len);
            msg = MessageFactory::create(mtype);
            if(msg.get()==nullptr)
            {
                ELOG("消息类型错误，构造的消息对象失败");
                return false;
            }
            bool ret = msg->unserialize(body);
            if(ret==false)
            {
                ELOG("消息正文反序列化失败");
                return false;
            }
            msg->setId(id);
            msg->setMType(mtype);
            return true;
        }
        //序列化消息
        virtual std::string serialize(const BaseMessage::ptr &msg) override
        {
            std::string body = msg->serialize();
            std::string id = msg->rid();
            auto mtype = htons((int32_t)msg->mtype());
            int32_t idlen = htonl(id.size());
            int32_t h_total_len = mtypeFieldsLength+idlenFieldsLength+id.size()+body.size();
            int32_t n_total_len = htonl(h_total_len);
            std::string result;//结果
            result.reserve(h_total_len);
            result.append((char*)&n_total_len,lenFieldsLength);
            result.append((char*)&mtype,mtypeFieldsLength);
            result.append((char*)&idlen,idlenFieldsLength);
            result.append(body);
            return result;
        }
        private:
        const size_t lenFieldsLength = 4;//
        const size_t mtypeFieldsLength = 4;//方法类型字段长度
        const size_t idlenFieldsLength = 4;//id 字段长度
    };
    class ProtocolFactory
    {
        public:
        template<typename ...Args>
        static BaseProtocol::ptr create(Args&& ...args)
        {
            return std::make_shared<LVProtocol>(std::forward<Args>(args));
        }
    };

    class MuduoConnection : public BaseConnection
    {
        public:
        using ptr = std::shared_ptr<MuduoConnection>;
        MuduoConnection(const muduo::net::TcpConnectionPtr &conn,const BaseProtocol::ptr &protocol)
        :_protocol(protocol),
         _conn(conn)
        {}
        //发送连接
        virtual void send(const BaseMessage::ptr &msg)override
        {
            std::string body = _protocol->serialize(msg);
            _conn->send(body);
        }
        virtual void shutdown()override//关闭连接
        {
            _conn->shutdown();
        }
        virtual bool connected()override
        {
            _conn->connected();
        }
        private:
        BaseProtocol::ptr _protocol;
        muduo::net::TcpConnectionPtr _conn;
    };
    class ConnectionFactory
    {
        public:
        template<typename ...Args>
        static BaseConnection::ptr create(Args&& ...args)
        {
            return std::make_shared<MuduoConnection>(std::forward<Args>(args));
        }
    };

    class MuduoServer:public BaseServer
    {
        public:
        using ptr = std::shared_ptr<MuduoServer>;
        MuduoServer(int port)
            :_server(&_baseloop,muduo::net::InetAddress("0.0.0.0",port),"MuduoServer",muduo::net::TcpServer::kNoReusePort),
            _protocol(ProtocolFactory::create())
            {}
            virtual void start()
            {
                _server.setConnectionCallback(std::bind(&MuduoServer::onConnection,this,std::placeholders::_1);
                _server.setMessageCallback(std::bind(&MuduoServer::onMessage,this,
                std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));
                _server.start();//开始监听
                _baseloop.loop();//一直循环事件监控
            }
            private:
            void onConnection(const muduo::net::TcpConnectionPtr &conn)
            {
                if(conn->connected())
                {
                    std::cout<<"建立成功\n";
                    auto muduo_conn = ConnectionFactory::create(conn,_protocol);
                    {
                        std::unique_lock<std::mutex> lock(_muext);
                        _conns.insert(std::make_pair(conn,muduo_conn));

                    }
                    if(_cb_connection)
                    {
                        _cb_connection(muduo_conn);
                    }
                }
                else
                {
                    
                }
            }
        private:
        const size_t maxDataSize = (1<<16);
        BaseProtocol::ptr _protocol;
        muduo::net::EventLoop _baseloop;
        muduo::net::TcpServer _server;
        std::mutex _muext;
        std::unordered_map<muduo::net::TcpConnectionPtr,BaseConnection::ptr>_conns;
    };
}